import React from 'react'
import createHashHistory from 'history/createHashHistory'
import document from 'global/document'
import { Provider } from 'react-redux'
import {
    routerMiddleware,
    routerReducer as reactRouterReduxRouterReducer
} from 'react-router-redux'
import * as core from 'dva-core'

export function dva (opts = {}) {
    const history = opts.history || createHashHistory()

    const createOpts = {
        initialReducer: {
            routing: reactRouterReduxRouterReducer,
        },
        setupMiddlewares (middlewares) {
            return [
                routerMiddleware(history),
                ...middlewares
            ]
        },
        setupApp (app) {
            app._history = patchHistory(history)
        }
    }

    const app = core.create(opts, createOpts)   // dva opts, dva construct opts
    const oldAppStart = app.start
    
    app.router = router // 直接设置router
    app.start = start   // 渲染或返回组件
    return app

    function router (router) {
        invariant(
            isFunction(router),
            `[app.router] router should be function, but got ${typeof router}`
        )
        app._router = router
    }

    function start (container) {
        if (isString(container)) container = document.querySelector(container)
        invariant(
            !container || isHTMLElement(container),
            `[app.start] container should be HTMLElement container必须不存在或者是htmlElement`
        )

        invariant(
            app._router,
            `[app.start] router must be registered before app.start()`
        )

        if (!app._store) {  // 如果_store不存在, 则进行core.create().start
            oldAppStart.call(app)
        }
        const store = app._store

        // 为了热更新  https://github.com/dvajs/dva/issues/469
        app._getProvider = _getProvider.bind(null, store, app)

        // 如果存在就渲染，不存在就返回组件
        if (container) {
            render(container, store, app, app._router)  // 渲染
            app._plugin.apply('onHmr')(render.bind(null, container, store, app))    // 热更新
        } else {
            return getProvider(store, this, this._router)
        }
    }

    function getProvider (store, app, router) {
        const DvaRoot = extraProps => ( // 其他的Props
            <Provider store={store}>
                { router({app, history: app._history, ...extraProps})}
            </Provider>
        )
        return DvaRoot
    }

    function render (container, store, app, router) {
        const ReactDom = require('react-dom')
        ReactDom.render(
            React.createElement(getProvider(store, app, router)),
            container
        )
    }

    function patchHistory (history) {
        const oldListen = history.listen
        history.listen = (callback) => {
            callback(history.location)  // 每次listen前执行一次callback, 参数是location
            return oldListen.call(history, callback)
        }
        return history
    }
}